package com.haredot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haredot.constraint.RabbitConst;
import com.haredot.constraint.RedisConst;
import com.haredot.controller.LoginController;
import com.haredot.dto.EmailDTO;
import com.haredot.dto.FindPwdDTO;
import com.haredot.dto.ModifyUserDTO;
import com.haredot.entity.*;
import com.haredot.event.RssNotifyEvent;
import com.haredot.event.enums.NotifyType;
import com.haredot.holder.TokenContextHolder;
import com.haredot.mapper.*;
import com.haredot.properties.JwtProperties;
import com.haredot.service.UserService;
import com.haredot.utils.JwtUtils;
import com.haredot.utils.RSA;
import com.haredot.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;

import javax.annotation.Resource;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Transactional(rollbackFor = Exception.class)
@EnableConfigurationProperties(JwtProperties.class)
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RSA rsa;

    @Resource
    private UserScoreMapper userScoreMapper;

    @Resource
    private ScoreConfigMapper scoreConfigMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private AuthorizeUserMapper authorizeUserMapper;

    @Resource
    private AttentionMapper attentionMapper;

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public R<?> registerOne(UserOneVo userOneVo) {

        // 判断 userOneVo 中是否 包含 uid, type, 和 sign
        if (StringUtils.hasLength(userOneVo.getUid()) && StringUtils.hasLength(userOneVo.getType()) && StringUtils.hasLength(userOneVo.getSign())) {
            // 进行数字认证
            String message = "uid=" + userOneVo.getUid() + "&method=oauth2&type=" + userOneVo.getType();
            // 进行数字认证
            if (!rsa.verify(message, URLDecoder.decode(userOneVo.getSign(), StandardCharsets.UTF_8))) {
                return R.fail("签名错误").build();
            }
        }

        // 根据 手机号 查询 改手机号是否已被注册
        User u = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getTel, userOneVo.getTel()));

        if (u != null) return R.fail(R.StatusCode.BAD).data(Map.of("tel", "手机号已被注册"));

        // 根据邮箱查询 该邮箱是否已被注册
        u = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, userOneVo.getEmail()));
        if (u != null) return R.fail(R.StatusCode.BAD).data(Map.of("email", "邮箱已被注册"));

        User user = new User();
        // 将参数 拷贝到 User 中
        user.setTel(userOneVo.getTel());
        user.setEmail(userOneVo.getEmail());
        user.setPassword(passwordEncoder.encode(userOneVo.getPassword())); // 密码加密
        user.setState(false); // 设置激活状态
        // 将用户信息写入到表中
        this.getBaseMapper().insert(user);

        // 绑定第三方账号
        if (StringUtils.hasLength(userOneVo.getUid()) && StringUtils.hasLength(userOneVo.getType())) {
            // 进行数字认证
            bindAccount(user, userOneVo.getType(), userOneVo.getUid());
        }

        String message = "uid=" + user.getId() + "&step=one";
        // 对 uid 进行签名，防止篡改
        String sign = rsa.sign(message);
        // 雪花算法ID 过大，JS 会将后三位 转变，必须传入字符串才可以
        return R.ok().data(Map.of("uid", String.valueOf(user.getId()), "sign", URLEncoder.encode(sign, StandardCharsets.UTF_8)));
    }

    @Override
    public R<?> registerTwo(UserTwoVo userTwoVo) {
        User user = new User();
        user.setId(userTwoVo.getUserId());
        user.setBirth(userTwoVo.getBirth());
        user.setAvatar(userTwoVo.getAvatar());
        user.setRealName(userTwoVo.getRealName());
        user.setNickName(userTwoVo.getNickName());
        user.setSex(userTwoVo.getSex());

        // 对 uid 进行签名，防止篡改
        if (rsa.verify("uid=" + user.getId() + "&step=one", URLDecoder.decode(userTwoVo.getSign(), StandardCharsets.UTF_8))) {
            this.getBaseMapper().updateById(user);
            String message = "uid=" + user.getId() + "&step=two";
            // 对 uid 进行签名，防止篡改
            String sign = rsa.sign(message);
            return R.ok().data(Map.of("uid", String.valueOf(user.getId()), "sign", URLEncoder.encode(sign, StandardCharsets.UTF_8)));
        }
        return R.fail("签名解析失败").build();
    }

    @Override
    public R<?> registerThree(UserThreeVo userThreeVo) {

        String sign = userThreeVo.getSign();
        sign = URLDecoder.decode(sign, StandardCharsets.UTF_8);

        String message = "uid=" + userThreeVo.getUserId() + "&step=" + userThreeVo.getStep();

        if (!rsa.verify(message, sign)) {
            return R.fail("签名解析失败").build();
        }

        final String redisKey = MessageFormat.format(RedisConst.ACCOUNT_ACTIVE, String.valueOf(userThreeVo.getUserId()));
        // 根据 userId , 查询对应的用户信息
        User user = this.getBaseMapper().selectById(userThreeVo.getUserId());
        // 判断 用户 激活状态，如果 已激活，则不做任何操作 , 判断是否该用户是否已经发送了邮件
        if (user.getState() || stringRedisTemplate.hasKey(redisKey)) return R.ok().data(Map.of("tel", user.getTel()));

        // 发送邮件，(暂不 激活用户， 暂不赠送积分)
        EmailDTO emailDTO = new EmailDTO();

        emailDTO.setSubject("【爱下载资源分享平台】用户注册-账户激活");
        emailDTO.setTo(user.getEmail());

        // 设置 邮件内容
        String content = """
                <div style="width:800px; border:3px solid lightblue; border-radius: 10px;padding:10px 20px;">
                    <h3 style="text-align: center">爱下载资源分享平台-用户注册账户激活</h3>
                    <p>
                        尊敬的手机号为<span style="color: #f00">{0}</span>的用户 ：
                    </p>
                    <p style="text-indent:25px">
                        感谢您于<b>{1}</b>注册账户，成为本网站的会员用户。提示码: <b style="padding: 2px 5px; border:1px solid #efefef;">{2}</b>
                        <br/>
                        点击下方激活链接，即可完成账户激活。
                    </p>
                    <p>
                        <a href="{3}">{3}</a>
                    </p>
                    <p>
                        该链接将会在10分钟后失效、如不是本人操作，忽略该邮件即可！
                    </p>
                    <p><b>【爱下载资源分享平台官方】</b></p>
                </div>
                """;

        String code = generatorCode(6);

        LocalDateTime now = LocalDateTime.now();
        String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(now);

        sign = rsa.sign("code=" + code + "&_time=" + time + "&uid=" + user.getId());
        // 生成超链接
        String linkUrl = MvcUriComponentsBuilder.fromMethodName(LoginController.class, "activeAccount", user.getId(), code, time, userThreeVo.getReferer(), URLEncoder.encode(sign, StandardCharsets.UTF_8)) // 路径参数 UID
                .encode() // 进行编码
                .build().toString();

        // 格式化文本内容
        content = MessageFormat.format(content, user.getTel(), time, code, linkUrl);

        emailDTO.setContent(content);
        emailDTO.setUserId(user.getId() + "");
        emailDTO.setCode(code);

        // 发送到 rabbitmq 中
        rabbitTemplate.convertAndSend("", RabbitConst.EMAIL_QUEUE, emailDTO);

        // 向 redis 中记录 激活过期时间 10分钟
        stringRedisTemplate.opsForValue().set(redisKey, code, Duration.ofMinutes(10));

        return R.ok().data(Map.of("tel", user.getTel(), "code", code, "email", user.getEmail()));
    }


    @Override
    public R<?> active(Map<String, Object> params) {
        String code = (String) params.get("code");
        String time = (String) params.get("time");
        String sign = (String) params.get("sign");
        Long userId = (Long) params.get("uid");

        final String redisKey = MessageFormat.format(RedisConst.ACCOUNT_ACTIVE, String.valueOf(userId));

        sign = URLDecoder.decode(sign, StandardCharsets.UTF_8);
        // 认证参数
        if (rsa.verify("code=" + code + "&_time=" + time + "&uid=" + userId, sign) && stringRedisTemplate.hasKey(redisKey)) {

            String codeRedis = stringRedisTemplate.opsForValue().get(redisKey);
            // 如果 redis 中存储的 code 和 传过来的 code 不相同，则失败
            if (!Objects.equals(codeRedis, code)) return R.fail("code编码不一致").build();
            // 激活账号
            LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<User>().set(User::getState, true).eq(User::getId, userId);
            // 如果没有问题，则准备 激活账号， 赠送积分
            this.getBaseMapper().update(null, userLambdaUpdateWrapper);

            // 赠送积分, 查询需要赠送的积分
            ScoreConfig scoreConfig = scoreConfigMapper.selectOne(new QueryWrapper<ScoreConfig>().eq("action", "用户注册").eq("state", true));

            if (scoreConfig != null) {
                UserScore userScore = UserScore.builder().action("用户注册").userId(userId).score(scoreConfig.getScore()).build();
                // 赠送积分
                userScoreMapper.insert(userScore);
            }
            // 一旦激活账户 ， 链接地址 失效
            stringRedisTemplate.delete(redisKey);

            return R.ok().build();
        }

        return R.fail("链接地址已失效").build();
    }

    private String generatorCode(int n) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

    @Override
    public R<?> getEmailCode(String email, String subject) {
        // 根据邮箱、查询该邮箱是否被注册
        User user = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));

        if (user == null) return R.fail("邮箱账号不存在").build();

        EmailDTO emailDTO = new EmailDTO();
        emailDTO.setUserId(String.valueOf(user.getId()));
        emailDTO.setCode(null);
        emailDTO.setTo(email);
        emailDTO.setSubject("【爱下载资源分享平台】" + subject + "-验证码");

        String content = """
                <div style="height: 170px; width:600px; border: 3px solid lightblue;border-radius: 10px;padding:10px 20px;">
                    <h3 style="text-align: center">爱下载资源分享平台-{0}验证码</h3>
                    <p>
                        尊敬的邮箱为<span style="color: #f00">{1}</span>的用户 ：您本次的验证码是:
                        <b style="padding: 2px 8px; border:1px solid #999; color:#f00; border-radius: 5px;">{2}</b>
                    </p>
                    <p>
                        该验证码将会在5分钟后失效、如不是本人操作，忽略该邮件即可！
                    </p>
                    <p><b>【爱下载资源分享平台官方】</b></p>
                </div>
                """;

        String code = generatorCode(6);

        String action = Base64.getEncoder().encodeToString(subject.getBytes(StandardCharsets.UTF_8));
        // 验证码 存储到 redis 中， 并设置 5分钟后失效 （设置幂等性操作，用户不允许在  1 分钟内多次发送邮件）
        if (stringRedisTemplate.opsForValue().setIfAbsent("rss:email:" + email + ":" + action, code, Duration.ofMinutes(1))) {
            // 格式化内容
            content = MessageFormat.format(content, subject, email, code);

            emailDTO.setContent(content);
            // 如果邮箱账号存在，则 准备发送邮件 进行登录
            rabbitTemplate.convertAndSend(RabbitConst.EMAIL_QUEUE, emailDTO);
            if ("邮箱登录".equals(subject)) {
                // 设置 验证码 5分钟有效期
                stringRedisTemplate.opsForValue().set(MessageFormat.format(RedisConst.EMAIL_LOGIN_CODE, email), code, Duration.ofMinutes(5));
            } else if ("找回密码".equals(subject)) {
                stringRedisTemplate.opsForValue().set(MessageFormat.format(RedisConst.EMAIL_PASSWORD_FIND_CODE, email), code, Duration.ofMinutes(5));
            }
        }

        this.log.info("您的邮箱验证码是:{}" , code);

        return R.ok().build();
    }

    /**
     * 邮箱登录
     *
     * @param email
     * @param code
     * @return
     */
    @Override
    public R<?> login(String email, String code) throws Exception {
        // 根据邮箱、查询对应的账号信息
        User user = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));

        if (user == null) return R.fail("邮箱账号不存在").build();

        // 获取 code 验证码 是否 正确
        String redisCode = stringRedisTemplate.opsForValue().get(MessageFormat.format(RedisConst.EMAIL_LOGIN_CODE, email));

        if (!StringUtils.hasLength(redisCode)) return R.fail("验证码不存在或已过期").build();

        if (!code.equals(redisCode)) return R.fail("验证码不正确").build();
        // 删除 验证码
        stringRedisTemplate.delete(MessageFormat.format(RedisConst.EMAIL_LOGIN_CODE, email));
        // 如果验证码 正确， 则代表 登录成功 ，校验用户信息
        UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
        // 校验用户信息
        try {
            userDetailsChecker.check(user);
            // 没有多大问题，准备生成 令牌信息
            Map<String, Object> ret = JwtUtils.generatorToken(stringRedisTemplate, user, jwtProperties, true, true, false);
            return R.ok().data(ret);

        } catch (AuthenticationException e) {
            return R.fail(e.getMessage()).build();
        }

    }

    @Override
    public R<?> bindAccount(String uid, String type, String sign, String tel, String password) {
        String message = "uid=" + uid + "&method=oauth2&type=" + type;
        // 进行数字认证
        if (!rsa.verify(message, URLDecoder.decode(sign, StandardCharsets.UTF_8))) {
            return R.fail("签名错误").build();
        }
        // 根据手机号查询账号信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(tel);

        if (userDetails == null) return R.fail("手机号或者密码不正确").build();

        if (userDetails instanceof User user) {
            // 比较密码 
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                return R.fail("手机号或者密码不正确").build();
            }
            // 如果验证码 正确， 则代表 登录成功 ，校验用户信息
            UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
            try {
                // 校验用户信息
                userDetailsChecker.check(user);

                // 绑定第三方账号
                bindAccount(user, type, uid);

                // 没有多大问题，准备生成 令牌信息
                Map<String, Object> ret = JwtUtils.generatorToken(stringRedisTemplate, user, jwtProperties, true, true, false);
                return R.ok().data(ret);
            } catch (Exception e) {
                return R.fail(e.getMessage()).build();
            }
        }
        return R.fail().build();
    }

    private int bindAccount(User user, String type, String uid) {
        // 根据用户id 查询 该用户 是否曾经绑定过其它 登录方式
        AuthorizeUser authorizeUser = authorizeUserMapper.selectOne(new LambdaQueryWrapper<AuthorizeUser>().eq(AuthorizeUser::getUserId, user.getId()));

        if (authorizeUser == null) {
            authorizeUser = new AuthorizeUser();
            // 获取 用户ID
            authorizeUser.setUserId(user.getId());
        }

        // 绑定用户和 第三方的用户ID的关系
        switch (type) {
            case "alipay" -> authorizeUser.setAlipayUserId(uid);
            case "wx" -> authorizeUser.setWxUserId(uid);
            case "qq" -> authorizeUser.setQqUserId(uid);
            case "sina" -> authorizeUser.setSinaUserId(uid);
            case "github" -> authorizeUser.setGithubUserId(uid);
            default -> throw new RuntimeException("第三方登录暂不支持该类型");
        }

        return authorizeUser.getId() == null ? authorizeUserMapper.insert(authorizeUser) : authorizeUserMapper.updateById(authorizeUser);
    }

    @Override
    public R<?> attentionUser(Long toUserId) {
        // 获取 当前用户信息
        Long currentUserId = TokenContextHolder.getCurrentUserId();

        Attention attention = attentionMapper.selectOne(new LambdaQueryWrapper<Attention>().eq(Attention::getFromUser, currentUserId).eq(Attention::getToUser, toUserId));

        Optional.ofNullable(attention).ifPresentOrElse(att -> {
            // 取消关注
            attentionMapper.deleteById(att);
        }, () -> {
            // 关注该用户
            Attention att = Attention.builder().fromUser(currentUserId).toUser(toUserId).build();
            attentionMapper.insert(att);

            // 查询当前登录的用户昵称
            User user = this.getBaseMapper().selectById(currentUserId);
            // 通知 toUserId 用户
            Notify notify = Notify.builder().userId(toUserId).typeName(NotifyType.ATTENT.getTypeName()).text("<b>" + (user.getNickName() != null ? user.getNickName() : telSecure(user.getTel())) + "</b>关注了您").build();
            // 发送通知
            applicationEventPublisher.publishEvent(new RssNotifyEvent(this, notify));
        });

        return R.ok().build();
    }

    @Override
    public R<?> modifyUser(ModifyUserDTO modifyUserDTO) {

        String oldEmail = modifyUserDTO.getOldEmail();
        if (StringUtils.hasLength(oldEmail)) {
            // 根据邮箱查询该邮箱是否存在，
            User user = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getId, modifyUserDTO.getId()).eq(User::getEmail, oldEmail));

            if (user == null) {
                return R.fail(R.StatusCode.BAD, "原邮箱不存在").build();
            }
            // 查询 新邮箱是否已经绑定账号
            Long count = this.getBaseMapper().selectCount(new LambdaQueryWrapper<User>().eq(User::getEmail, modifyUserDTO.getNewEmail()));

            if (count > 0) {
                return R.fail("新邮箱已被其它账号绑定").build();
            }
        }
        // 如果要修改密码
        if (StringUtils.hasLength(modifyUserDTO.getOldPassword())) {
            User user = this.getBaseMapper().selectOne(new LambdaQueryWrapper<User>().eq(User::getId, modifyUserDTO.getId()));

            if (user == null || !passwordEncoder.matches(modifyUserDTO.getOldPassword(), user.getPassword())) {
                return R.fail("原密码不正确").build();
            }
        }

        // 进行更新操作
        this.getBaseMapper().update(null, new LambdaUpdateWrapper<User>().set(StringUtils.hasLength(modifyUserDTO.getAvatar()), User::getAvatar, modifyUserDTO.getAvatar()).set(StringUtils.hasLength(modifyUserDTO.getNickName()), User::getNickName, modifyUserDTO.getNickName()).set(StringUtils.hasLength(modifyUserDTO.getNewEmail()), User::getEmail, modifyUserDTO.getNewEmail()).set(StringUtils.hasLength(modifyUserDTO.getSex()), User::getSex, modifyUserDTO.getSex()).set(StringUtils.hasLength(modifyUserDTO.getNewPassword()), User::getPassword, passwordEncoder.encode(modifyUserDTO.getNewPassword())).eq(User::getId, modifyUserDTO.getId()));

        return R.ok().data(modifyUserDTO.getAvatar());
    }

    private String telSecure(String tel) {
        if (!tel.matches("^1[3-9]\\d{9}$")) return tel;
        return tel.substring(0, 3) + "****" + tel.substring(7);
    }

    @Override
    public R<Page<UserScoreVo>> queryUserScores(Page<UserScoreVo> page) {
        Long userId = TokenContextHolder.getCurrentUserId();
        // 分页查询 数据
        Page<UserScoreVo> data = this.getBaseMapper().findUserScores(page, userId);

        return R.<Page<UserScoreVo>>ok().data(data);
    }

    @Override
    public R<Map<String, Object>> queryScoreShapeDetails() {
        // 获取当前登录的用户ID
        Long userId = TokenContextHolder.getCurrentUserId();
        // 查询 总积分、粉丝数、关注数、积分来源统计
        List<Map<String, String>> list = this.getBaseMapper().findTotalScoreAndFansAndAttachAndRemarks(userId);
        // 存储最终的结果
        Map<String, Object> ret = new HashMap<>();
        List<Map<String, String>> scoreDetails = new ArrayList<>();
        list.forEach(map -> {
            if ("score".equals(map.get("name")) || "fans".equals(map.get("name")) || "attach".equals(map.get("name"))) {
                ret.put(map.get("name"), map.get("value"));
            } else {
                scoreDetails.add(map);
            }
        });
        ret.put("scoreDetails", scoreDetails);

        return R.<Map<String, Object>>ok().data(ret);
    }

    @Override
    public R<UserFriendsVo> queryFriendList() {
        // 获取当前登录的用户ID
        Long userId = TokenContextHolder.getCurrentUserId();
        // 查询好友信息
        List<UserFriendsVo> userFriendsVoPage = this.getBaseMapper().findUserFriends(userId);

        return R.<UserFriendsVo>ok().data(userFriendsVoPage);
    }

    @Override
    public R<UserFriendsVo> queryFriendDetail(Long uid) {
        // 获取当前登录的用户ID
        Long userId = TokenContextHolder.getCurrentUserId();

        UserFriendsVo userFriendsVo = this.getBaseMapper().findUserFriend(userId, uid);

        return R.<UserFriendsVo>ok().data(userFriendsVo);
    }

    @Override
    public R<?> findPasswordByEmail(FindPwdDTO findPwdDTO) {
        String redisKey = MessageFormat.format(RedisConst.EMAIL_PASSWORD_FIND_CODE, findPwdDTO.getEmail());
        // 比较验证码是否和 redis 中存储的一致
        String code = stringRedisTemplate.opsForValue().get(redisKey);
        if (!StringUtils.hasLength(code) || !Objects.equals(code, findPwdDTO.getCode())) {
            return R.fail("验证码不正确").build();
        }
        // 验证码正确，删除该验证码
        stringRedisTemplate.delete(redisKey) ;
        // 修改对应邮箱账号的密码为新密码
        int len = this.getBaseMapper().update(null, new LambdaUpdateWrapper<User>()
                .set(User::getPassword, passwordEncoder.encode(findPwdDTO.getPassword())).eq(User::getEmail, findPwdDTO.getEmail()));

        return len == 1 ? R.ok().build() : R.fail().build();
    }

    @Override
    public R<?> checkFriend(Long uid) {
        Long currentUserId = TokenContextHolder.getCurrentUserId();
        // 检查 是否关注了 uid , 或者 uid 关注了你
        long count = this.getBaseMapper().findAttentionCount(currentUserId, uid);

        if (count == 0) {
            return R.fail("请先关注后再进行私聊").build();
        }
        // 查询 是否被 对方加入了黑名单
        UserBlack userBlack = this.getBaseMapper().findBlackByUid(currentUserId, uid);

        if (userBlack != null) {
            return R.fail("您被对方加入了黑名单、无法进行私聊").build();
        }

        return R.ok().build();
    }
}
